package com.ztesoft.book.core.sys.sysuser.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.crypto.SmUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ztesoft.book.common.utils.encrypt.AesEncryptSm4Util;
import com.ztesoft.book.common.utils.exception.ServiceException;
import com.ztesoft.book.core.base.base.service.impl.BaseExServiceImpl;
import com.ztesoft.book.core.sys.sysmenu.dto.SysMenuDTO;
import com.ztesoft.book.core.sys.sysmenu.qo.LoginMenuTreeNewQO;
import com.ztesoft.book.core.sys.sysmenu.qo.LoginMenuTreeQO;
import com.ztesoft.book.core.sys.sysuser.dto.SysUserDTO;
import com.ztesoft.book.core.sys.sysuser.mapper.SysUserMapper;
import com.ztesoft.book.core.sys.sysuser.qo.SysUserQO;
import com.ztesoft.book.core.sys.sysuser.service.SysUserService;
import com.ztesoft.book.core.sys.sysuser.vo.SysUserPwdVO;
import com.ztesoft.book.core.sys.sysuser.vo.SysUserSafeVO;
import com.ztesoft.book.core.sys.sysuserrole.dto.SysUserRoleDTO;
import com.ztesoft.book.core.sys.sysuserrole.service.SysUserRoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * @Description 系统用户
 * @Author YangFan
 * @Date 2021-06-22 17:32
 */
@Slf4j
@Service("sysUserService")
public class SysUserServiceImpl extends BaseExServiceImpl<SysUserMapper, SysUserDTO, SysUserQO> implements SysUserService {

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private SysUserRoleService sysUserRoleService;

    protected static final String PARENT_ID = "0";

    @Override
    protected SysUserMapper getMapper() {
        return sysUserMapper;
    }


    @Override
    public String getPermissionByUser(String userid) {
        String permisission = "";
        List<SysMenuDTO> menulist = sysUserMapper.findMenuByUser(userid);
        permisission = menulist.stream()
                .map(SysMenuDTO::getPermission)
                .filter(x -> x != null)
                .collect(Collectors.joining(","));
        return permisission;
    }



    @Override
    public List<LoginMenuTreeNewQO> getLoginUserMenuByUserNew(String userid) {
        // 获取非按钮菜单
        List<LoginMenuTreeNewQO> menulist = sysUserMapper.findMenuByUserWithOutButton(userid);
        List<LoginMenuTreeNewQO> list = new ArrayList<>();
        getMenuTree(list, PARENT_ID, menulist);
        return list;
    }


    /**
     * 方法功能描述:
     * < 递归获取列表 >
     *
     * @param list        参数说明
     * @param parentId    参数说明
     * @param sysMenuDTOS 参数说明
     * @return void
     * @author YangFan
     * @date 2021-09-01 15:25
     */
    private void getMenuTree(List<LoginMenuTreeNewQO> list, String parentId, List<LoginMenuTreeNewQO> sysMenuDTOS) {
        //获取子类
        List<LoginMenuTreeNewQO> childrenList = sysMenuDTOS.stream().filter(setting -> {
                    return setting.getParentId().equals(parentId);
                }).collect(Collectors.toList());
        for (LoginMenuTreeNewQO sysMenuDTO : childrenList) {
            List<LoginMenuTreeNewQO> children = new ArrayList<>();
            getMenuTree(children, sysMenuDTO.getId(), sysMenuDTOS);
            if (!children.isEmpty()) {
                sysMenuDTO.setSubMenu(children);
            }
            list.add(sysMenuDTO);
        }
    }


    /**
     * 匹配正则表达式方法
     *
     * @param regEx 正则
     * @param str   字符串
     * @return boolean
     */
    private boolean matcherRegularExpression(String regEx, String str) {
        Pattern pattern = Pattern.compile(regEx);
        Matcher matcher = pattern.matcher(str);
        boolean found = false;
        while (matcher.find()) {
            found = true;
        }
        return found;
    }

    /**
     * 校验面是否符合规范
     *
     * @return
     */
    private void checkPwd(String content) {
        if (content.length() < 8 || content.length() > 16) {
            throw new ServiceException("请填写8到16位的密码");
        }

        int num = 0;
        if (matcherRegularExpression("([a-z])+", content)) {
            num++;
        }

        if (matcherRegularExpression("([0-9])+", content)) {
            num++;
        }

        if (matcherRegularExpression("([A-Z])+", content)) {
            num++;
        }

        if (matcherRegularExpression("[^a-zA-Z0-9]+", content)) {
            num++;
        }
        if (num < 3) {
            throw new ServiceException("密码必须是字母大写，字母小写，数字，特殊字符中任意三个组合");
        }

    }


    /**
     * 修改密码
     *
     * @param sysUserPwdVO
     */
    @Override
    public void updatePwd(SysUserPwdVO sysUserPwdVO) {
        SysUserDTO sysUserDTO = this.getMapper().selectById(sysUserPwdVO.getId());
        if (sysUserDTO == null) {
            throw new ServiceException("用户不存在");
        }
        //旧密码判断。
        String username = AesEncryptSm4Util.desEncrypt(sysUserDTO.getUsername());
        String key = SmUtil.sm3(sysUserDTO.getSalt() + sysUserPwdVO.getOldPwd());
        if (!key.equals(sysUserDTO.getPassword())) {
            throw new ServiceException("密码不正确");
        }
        //密码和用户名不能一样
        if (username.equals(sysUserPwdVO.getNewPwd())) {
            throw new ServiceException("密码和用户名一致，修改失败");
        }


        checkPwd(sysUserPwdVO.getNewPwd());
        //新密码设置。
        String newKey = SmUtil.sm3(sysUserDTO.getSalt() + sysUserPwdVO.getNewPwd());
        if (key.equals(newKey)) {
            throw new ServiceException("新密码和旧密码一致，修改失败");
        }

        SysUserDTO updateDto = new SysUserDTO();
        updateDto.setId(sysUserPwdVO.getId());
        updateDto.setPassword(newKey);
        updateDto.setModifyPwd(1);
        updateDto.setModifyPwdTime(LocalDateTime.now());
        this.getMapper()
                .updateById(updateDto);

    }


    /**
     * 方法功能描述:
     * < 组装嵌套二级菜单到一级导航下 >
     *
     * @param zeroList 【参数 1 注释说明】
     * @param oneList  【参数 2 注释说明】
     * @return List list
     * @author YangFan
     * @date 2021-07-02 15:44
     */
    public List<LoginMenuTreeQO> createTreeMenu(List<SysMenuDTO> zeroList, List<SysMenuDTO> oneList) {
        List<LoginMenuTreeQO> menulist = new ArrayList<>();
        if (!zeroList.isEmpty()) {
            for (SysMenuDTO zeroObj : zeroList) {
                LoginMenuTreeQO pmenu = new LoginMenuTreeQO(true, true, true, true);
                pmenu.setName(zeroObj.getName());
                pmenu.setIcon(zeroObj.getIcon());
                pmenu.setPath(zeroObj.getUrl());
                pmenu.setComponent(zeroObj.getComponent());

                List<LoginMenuTreeQO> cmenuList = new ArrayList<>();
                if (!oneList.isEmpty()) {
                    for (SysMenuDTO oneObj : oneList) {
                        // 如果子菜单的pid 等于 父菜单，则加入子List
                        if (oneObj.getParentId()
                                .equals(zeroObj.getId())) {
                            LoginMenuTreeQO cmenu = new LoginMenuTreeQO(true, true, true, true);
                            cmenu.setName(oneObj.getName());
                            cmenu.setIcon(oneObj.getIcon());
                            cmenu.setPath(oneObj.getUrl());
                            cmenu.setComponent(oneObj.getComponent());
                            cmenu.setRoutes(new ArrayList<>());
                            cmenuList.add(cmenu);
                        }
                    }
                }
                pmenu.setRoutes(cmenuList);

                menulist.add(pmenu);
            }
        }
        return menulist;
    }


    @Override
    public PageInfo<SysUserSafeVO> findPageSafe(SysUserQO qo, final Integer current, final Integer pageSize) {
        if (current != null && pageSize != null) {
            PageHelper.startPage(current, pageSize, true);
        }
        List<SysUserSafeVO> listvo = sysUserMapper.findListSafe(qo);
        if (CollUtil.isEmpty(listvo)) {
            listvo = Collections.emptyList();
        }
        PageInfo pageInfo = new PageInfo(listvo);

        //用户名解密,获取权限
        List<SysUserSafeVO> list = pageInfo.getList();
        Map<String, SysUserSafeVO> sysUserDTOMap = new HashMap<>();
        for (SysUserSafeVO sysUserDTO : list) {
            sysUserDTO.setUsername(AesEncryptSm4Util.desEncrypt(sysUserDTO.getUsername()));
            sysUserDTO.setRoleIdList(new ArrayList<>());
            sysUserDTOMap.put(sysUserDTO.getId(), sysUserDTO);
        }
        //查询权限。
        List<SysUserRoleDTO> roleDTOS = sysUserRoleService.getListByUserIds(sysUserDTOMap.keySet());
        //设置人员权限
        for (SysUserRoleDTO roleDTO : roleDTOS) {
            sysUserDTOMap.get(roleDTO.getUserId())
                    .getRoleIdList()
                    .add(roleDTO.getRoleId());
        }
        return pageInfo;
    }


}